package com.charles.seckillGateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.charles.seckillGateway.service.CaptchaService;
import com.charles.seckillcommon.core.utils.WebFluxUtil;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import javax.annotation.Resource;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Charles-H
 * 
 * 验证码校验拦截器
 */
@Component
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> {
    
    private final static String FILTER_PATH = "/auth/register";
    
    private final static String CODE = "code";
    
    private final static String UUID = "uuid";
    
    @Resource
    private CaptchaService captchaService;


    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            /* 对登录路径进行拦截 */
            if (!request.getURI().getPath().equals(FILTER_PATH)) return chain.filter(exchange);

            try {
                String rspStr = resolveBodyFromRequest(request);
                JSONObject obj = JSON.parseObject(rspStr);
                captchaService.verifyCaptcha(obj.getString(CODE), obj.getString(UUID));
            } catch (Exception e) {
                return WebFluxUtil.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
            }

            return chain.filter(exchange);
        };
    }

    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        /* 获取请求体 */
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();

        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });

        return bodyRef.get();
    }
    
}
